#define _CRT_SECURE_NO_DEPRECATE
#include <Windows.h>
#include "Leg.h"
#include "Body.h"
#include "Neck.h"
#include "Face.h"
#include "butt.h"
#include "Lake.h"
#include "World.h"
#include <glut.h>
#include <math.h>
#include "Light.h"
#include "Giraffe.h"
#include "Tree.h"
using namespace std;

struct Perspective
{
	double lookX;
	double lookY;
	double lookZ;
};
// Light Properties
GLfloat vertices[][3]={{-10.,  -10.,  -10.},{ 10.,  -10.,  -10.},  
				 { 10.,   10.,  -10.},{-10.,   10.,  -10.},   
				 {-10.,  -10.,   10.},{ 10.,  -10.,   10.},   
				 { 10.,   10.,   10.},{-10.,   10.,   10.} };


GLfloat light0_pos[] = {0, 3, 0,   1.};       
float no_mat[] = {0.0f, 0.0f, 0.0f, 1.0f};
float mat_ambient[] = {0.7f, 0.7f, 0.7f, 1.0f};
float mat_ambient_color[] = {0.8f, 0.8f, 0.2f, 1.0f};
float mat_diffuse[] = {0.1f, 0.5f, 0.8f, 1.0f};
float mat_specular[] = {1.0f, 1.0f, 1.0f, 1.0f};
float no_shininess = 0.0f;
float low_shininess = 5.0f;
float high_shininess = 100.0f;
float mat_emission[] = {0.3f, 0.2f, 0.2f, 0.0f};

float proj_m[16] = {	1.0,  0.0,  0.0,   0.0 ,		
	0.0,  1.0,  0.0,  -0.228,  
	0.0,  0.0,  1.0,   0.0 ,		
	0.0,  0.0,  0.0,   0.0  };
int init=1;
int Sign = -1;
float Angle = 10;
int genAngle=0;
int genAngle1=0;
int genAngle2=0;
void cube();
Perspective mainPers;
GLUquadricObj *p;/* pointer to quadric object */
int num_texture = -1;
GLint id_texture;
//Leg *l1;
//Leg *l2;
//Leg *l3;
//Leg *l4;
//Body *MainBody;
//Neck *MainNeck;
//Face *mainFace;
//Butt *mainButt;
Lake *mainLake;
World *mainWorld;
Light *mainLight;
Giraffe *g[3];
Tree *t[5];
int currGiraffe = 0;
int genAnglearr[3]={0,0,0};
int LoadBitmap(char *filename) 
{
	// windows.h gives us these types to work with the Bitmap files
	BITMAPFILEHEADER fileheader; 
	BITMAPINFOHEADER infoheader;
	RGBTRIPLE rgb;

	num_texture ++; // The counter of the current texture is increased
	FILE *pFile = fopen( filename, "rb"); // Open the file for reading
	if( NULL == pFile ) return (-1);	
	fread( &fileheader, sizeof(fileheader), 1, pFile); // Read the fileheader
	fseek( pFile, sizeof(fileheader), SEEK_SET); // Jump the fileheader
	fread( &infoheader, sizeof(infoheader), 1, pFile); // and read the infoheader
	// Now we need to allocate the memory for our image (width * height * color deep)
	int nSize = infoheader.biWidth * infoheader.biHeight * 4;
	unsigned char *pTexture = (unsigned char *)new char[nSize];
	// And fill it with zeros
	ZeroMemory( pTexture, sizeof( char ) * nSize );
	// At this point we can read every pixel of the image
	int j = 0;

    for(int i=0; i<infoheader.biWidth * infoheader.biHeight; i ++ )
    {            
            // We load an RGB value from the file
            fread( &rgb, sizeof(rgb), 1, pFile); 
            // And store it
            pTexture[j+0] = rgb.rgbtRed;	// Red component
            pTexture[j+1] = rgb.rgbtGreen;	// Green component
            pTexture[j+2] = rgb.rgbtBlue;	// Blue component
            pTexture[j+3] = 255;			// Alpha value
            j += 4; // Go to the next position
    }
    fclose( pFile ); // Closes the file stream
     
    glBindTexture(GL_TEXTURE_2D, num_texture); // Bind the ID texture specified by the 2nd parameter
    // The next commands sets the texture parameters
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // If the u,v coordinates overflow the range 0,1 the image is repeated
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); // We don't combine the color with the original surface color, use only the texture map.
	   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
    // Finally we define the 2D texture
    glTexImage2D(GL_TEXTURE_2D, 0, 4, infoheader.biWidth, infoheader.biHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, pTexture);
    // And create 2d mipmaps for the minifying function
    gluBuild2DMipmaps(GL_TEXTURE_2D, 4, infoheader.biWidth, infoheader.biHeight, GL_RGBA, GL_UNSIGNED_BYTE, pTexture);
	delete[] pTexture;  // Free the memory we used to load the texture
	return num_texture; // Returns the current texture OpenGL ID

}


void DrawGiraffe(void)
{
	gluLookAt(0 + mainPers.lookX, 0 + mainPers.lookY, 15 + mainPers.lookZ, 0., 0., 0., 0., 10., 0.);

	mainWorld->Draw();
	glPushMatrix();
	 glRotatef(genAnglearr[0],0,1,0);
	 g[0]->Draw();
	glPopMatrix();
	glPushMatrix();
	 glRotatef(genAnglearr[1]+90,0,1,0);
	 g[1]->Draw();
	glPopMatrix();
	glPushMatrix();
	 glRotatef(genAnglearr[2]+180,0,1,0);
	 g[2]->Draw();	
	glPopMatrix();

	mainLake->DrawHip();

}
void display(void) 
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glLoadIdentity();
	gluLookAt(0 + mainPers.lookX, 0 + mainPers.lookY, 15 + mainPers.lookZ, 0., 0., 0., 0., 10., 0.);
	//MainBody->SetAngle(90, 0,1,0);
	
	g[0]->MainNeck->SetAngle(90,1,0,0);
	g[1]->MainNeck->SetAngle(90,1,0,0);
	g[2]->MainNeck->SetAngle(90,1,0,0);
	glPushMatrix();
	
	t[0]->DrawHip();
	t[1]->DrawHip();
	t[2]->DrawHip();
	t[3]->DrawHip();
	t[4]->DrawHip();
	glPopMatrix();
	//mainFace->SetAngle(-90, 0,1,-0.2);
	//mainLight->Draw();

	glBindTexture( GL_TEXTURE_2D,id_texture ); // We set the active texture 
	cube();
	mainLight->Draw();
	DrawGiraffe();
	glFlush();
	glutSwapBuffers();  
}
void polygon(int a,int b, int c,int d)
{
	glBegin(GL_POLYGON);
	glTexCoord2f(0.,0.);
	glVertex3fv(vertices[a]);
	glTexCoord2f(0.,1.);
	glVertex3fv(vertices[b]);
	glTexCoord2f(1.,1.);
	glVertex3fv(vertices[c]);
	glTexCoord2f(1.,0.);
	glVertex3fv(vertices[d]);
	glEnd();
}
void cube()
{
	//polygon(0,3,2,1);
	//polygon(2,3,7,6);
	//polygon(0,4,7,3);
	//polygon(1,2,6,5);
	//polygon(4,5,6,7);
	//polygon(0,1,5,4);
}
void change_viewer( unsigned char key, int x, int y )
{

	if (key == 'n')
	{
		if(mainPers.lookY >0)		mainPers.lookY --;
	}

	if (key == 'm')
	{
		mainPers.lookY ++;
	}

	if (key == 'u')
	{
		mainPers.lookZ --;
	}

	if (key == 'i')
	{
		if(mainPers.lookZ < 111)
		mainPers.lookZ ++;
	}

	if (key == 'j')
	{
		mainPers.lookX --;
	}

	if (key == 'k')
	{
		if(mainPers.lookX  <=25)
		mainPers.lookX ++;
	}

	if (key=='f')
	{
		g[currGiraffe]->MainNeck->Move();
		g[currGiraffe]->mainFace->Move();
	}
	if(key == 'w')
	{

		if(Angle == 0)
		{
			Angle = 10;
		}
		else if (Angle == 10)
		{
			Angle = 1;
		}
		else if (Angle == 1)
		{
			Angle = -10;
		}
		else if (Angle == -10)
		{
			Angle = 0;
		}

		g[currGiraffe]->l1->SetAngle(Angle,0 ,1,0);
		g[currGiraffe]->l2->SetAngle(Angle, 0,1,0);
		g[currGiraffe]->l3->SetAngle(Angle*Sign, 0,1,0);
		g[currGiraffe]->l4->SetAngle(Angle*Sign,0 ,1,0);

		g[currGiraffe]->l4->SetLocation(-1,1,0,0);
		g[currGiraffe]->l3->SetLocation(-1,1,0,0);
		g[currGiraffe]->l2->SetLocation(-1,1,0,0);
		g[currGiraffe]->l1->SetLocation(-1,1,0,0);

		g[currGiraffe]->MainBody->SetLocation(-1,1,0,0);
		g[currGiraffe]->MainNeck->SetLocation(-1,1,0,0);
		g[currGiraffe]->mainFace->SetLocation(-1,1,0,0);
		g[currGiraffe]->mainButt->SetLocation(-1,1,0,0);
	}				
	if (key == 's')
	{
		if(Angle == 0)
		{
			Angle = 10;
		}
		else if (Angle == 10)
		{
			Angle = 1;
		}
		else if (Angle == 1)
		{
			Angle = -10;
		}
		else if (Angle == -10)
		{
			Angle = 0;
		}

		g[currGiraffe]->l1->SetAngle(Angle,0 ,1,0);
		g[currGiraffe]->l2->SetAngle(Angle, 0,1,0);
		g[currGiraffe]->l3->SetAngle(Angle*Sign, 0,1,0);
		g[currGiraffe]->l4->SetAngle(Angle*Sign,0 ,1,0);

		g[currGiraffe]->l4->SetLocation(1,1,0,0);
		g[currGiraffe]->l3->SetLocation(1,1,0,0);
		g[currGiraffe]->l2->SetLocation(1,1,0,0);
		g[currGiraffe]->l1->SetLocation(1,1,0,0);

		g[currGiraffe]->MainBody->SetLocation(1,1,0,0);
		g[currGiraffe]->MainNeck->SetLocation(1,1,0,0);
		g[currGiraffe]->mainFace->SetLocation(1,1,0,0);
		g[currGiraffe]->mainButt->SetLocation(1,1,0,0);
	}
	if (key == 'a')
	{

		genAnglearr[currGiraffe] +=2;
	}

	if (key == 'd')
	{
		genAnglearr[currGiraffe] -=2;
	}
	DrawGiraffe();
	glutPostRedisplay();

}
void myinit()
{
	GLfloat mat_specular[]={1.0,1.0,1.0,1.0};
	GLfloat mat_shininess[]={50.0};
	GLfloat light_position[]={0,10,5,0.0};
	GLfloat white_light[]={1.0,1.0,1.0,1.0};

	glClearColor(0.0,0.0,0.0,0.0);
	glShadeModel(GL_SMOOTH);

	glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular);
	glMaterialfv(GL_FRONT,GL_SHININESS,mat_shininess);
	glLightfv(GL_LIGHT0,GL_POSITION,light_position);
	glLightfv(GL_LIGHT0,GL_DIFFUSE,white_light);
	glLightfv(GL_LIGHT0,GL_SPECULAR,white_light);

	glEnable(GL_LIGHTING);
	glEnable(GL_LIGHT0);

	glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
	glEnable(GL_COLOR_MATERIAL); 

	mainPers.lookX = 26;
	mainPers.lookY = 6;
	mainPers.lookZ = 28;
	g[0]->l1->SetAngle(90,1,0,0);
	g[0]->l1->SetAngle(10,0,1,0);
	g[0]->l2->SetAngle(90,1,0,0);
	g[0]->l2->SetAngle(-10,0,1,0);
	g[0]->l3->SetAngle(90,1,0,0);
	g[0]->l3->SetAngle(-10,0,1,0);
	g[0]->l4->SetAngle(90,1,0,0);
	g[0]->l4->SetAngle(10,0,1,0);	
	g[0]->MainBody->SetAngle(90, 0,1,0);
	g[0]->MainNeck->SetAngle(90,1,0,0);
	g[0]->mainFace->SetAngle(-90, 0,1,0);
	g[1]->l1->SetAngle(90,1,0,0);
	g[1]->l1->SetAngle(10,0,1,0);
	g[1]->l2->SetAngle(90,1,0,0);
	g[1]->l2->SetAngle(-10,0,1,0);
	g[1]->l3->SetAngle(90,1,0,0);
	g[1]->l3->SetAngle(-10,0,1,0);
	g[1]->l4->SetAngle(90,1,0,0);
	g[1]->l4->SetAngle(10,0,1,0);	
	g[1]->MainBody->SetAngle(90, 0,1,0);
	g[1]->MainNeck->SetAngle(90,1,0,0);
	g[1]->mainFace->SetAngle(-90, 0,1,0);
	g[2]->l1->SetAngle(90,1,0,0);
	g[2]->l1->SetAngle(10,0,1,0);
	g[2]->l2->SetAngle(90,1,0,0);
	g[2]->l2->SetAngle(-10,0,1,0);
	g[2]->l3->SetAngle(90,1,0,0);
	g[2]->l3->SetAngle(-10,0,1,0);
	g[2]->l4->SetAngle(90,1,0,0);
	g[2]->l4->SetAngle(10,0,1,0);	
	g[2]->MainBody->SetAngle(90, 0,1,0);
	g[2]->MainNeck->SetAngle(90,1,0,0);
	g[2]->mainFace->SetAngle(-90, 0,1,0);
	glMaterialfv(GL_LIGHT0, GL_AMBIENT, no_mat);
	glMaterialfv(GL_LIGHT0, GL_DIFFUSE, mat_diffuse);
	glMaterialfv(GL_LIGHT0, GL_SPECULAR, no_mat);
	glMaterialf(GL_LIGHT0, GL_SHININESS, no_shininess);
	glMaterialfv(GL_LIGHT0, GL_EMISSION, no_mat);
	glLightfv(GL_LIGHT0, GL_POSITION, light0_pos);
	glViewport(0,0,800,600);
	glClearColor(1.0, 1.0, 1.0, 1.0);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(60, 1, 1, 400);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glEnable(GL_DEPTH_TEST); // We enable the depth test (also called z bu();ffer)

	glEnable(GL_TEXTURE_2D); // This Enable the Texture mapping
	id_texture = LoadBitmap("sky2.bmp"); 
	cube();
}
void menu(int id) {
	/* menu selects which angle to change or whether to quit */
	if(id == 1) currGiraffe=0;
	if(id == 2) currGiraffe=1;
	if(id == 3) currGiraffe=2; }

void main(int argc, char **argv) 
{

	p=gluNewQuadric(); /* allocate quadric object */
	gluQuadricDrawStyle(p, GLU_SMOOTH); /* render it as wireframe */
	id_texture = LoadBitmap("sky2.bmp"); 
	glEnable(GL_DEPTH_TEST);
	glEnable(GL_TEXTURE_2D);
	gluQuadricTexture(p,GL_TRUE);
	/*l1 = new Leg(3,5,-2,p, -1);
	l2 = new Leg(-3,5,-1,p, -1);
	l3 = new Leg(-3,5,1,p, -1);
	l4 = new Leg(3,5,2,p, -1);
	MainBody = new Body(-4, 6, 0, p, -1);
	MainNeck = new Neck(-4, 17, 0, p, -1);
	mainFace = new Face(-4, 18, 0, p, -1);
	mainButt = new Butt(4,6,0,p, -1);*/
	//t1 =new TRACKMOUSEEVE
	mainLake = new Lake(-30, 0, 2, p, -1);
	mainWorld = new World(p, num_texture);
	mainLight = new Light(-1, p);
	g[0] =new Giraffe(p,20);
	g[1] =new Giraffe(p,10);
	g[2] =new Giraffe(p,50);
	t[0] = new Tree(-50,-3,0,p,-1);
	t[1] = new Tree(-40,-3,0,p,-1);
	t[2] = new Tree(-30,-3,0,p,-1);
	t[3] = new Tree(-20,-3,0,p,-1);
	t[4] = new Tree(-10,-3,0,p,-1);
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
	glutInitWindowSize(800, 600);
	glutCreateWindow("Giraffes");
	glutCreateMenu(menu);
    glutAddMenuEntry("1st Giraffe", 1);
    glutAddMenuEntry("2nd Giraffe", 2);
    glutAddMenuEntry("3rd Giraffe", 3);
    glutAttachMenu(GLUT_LEFT_BUTTON);


	myinit();

	glutKeyboardFunc( change_viewer );
	glutDisplayFunc(display);
	glutMainLoop();
}
